<?php

namespace app\models;

use yii\base\Model;
use yii\log\FileTarget;

class CommonModel extends Model
{

    /**
     * 获取[PC]登录的用户编号
     * @return int|string
     */
    public static function getUid() {
        return \Yii::$app->getUser()->id;
    }

    /**
     * 获取[Mobile]登录的用户编号
     * @return int|string
     */
    public static function getAppUid() {
        return \Yii::$app->request->headers->get('uid');
    }

    /**
     * 获取图片服务器地址
     */
    public static function getUpYunHost()
    {

        // 暂时不开放第三方云存储，暂时本地域名即可
        // return \Yii::$app->params['UpYunConfig']['domain'];
        return self::getServerHost();
    }

    /**
     * 获取服务器地址
     */
    public static function getServerHost()
    {

        return \Yii::$app->request->hostInfo;
    }

    /**
     * 添加图片服务器 host主机
     * @param $path
     * @param null $key
     * @return array|string
     */
    public static function addImgHost($path, $key = null)
    {

        // 判断为空 直接返回null
        if (empty($path))

            return '';

        // 获取下params配置文件的第三方存储 查看域名
        $upYunHost = self::getUpYunHost();

        // 字符直接加上
        if (!is_array($path)) {

            // 如果这个链接有[host]就不添加 直接返回
            $stage = parse_url($path);
            if (!empty($stage['host']) && !empty($stage['scheme']))
                return $path;

            // 否则添加域名
            return $upYunHost . $path;
        }

        // 数组 妹哥循环添加
        $stage = '';
        foreach ($path as $k => $v) {

            // 空的直接吓一条
            if (empty($v))
                continue;

            // 如果这个链接有[host]就不添加
            $stage = !$key ? parse_url($v) : parse_url($v[$key]);
            if (!empty($stage['host']) && !empty($stage['scheme'])) {

                continue;
            }

            // 未传输KEY是一纬数组
            if (!$key) {

                $path[$k] = $upYunHost . $v;
                continue;
            }

            // 传输KEY是二维数组
            if ($key && !empty($v[$key]))
                $path[$k][$key] = $upYunHost . $v[$key];
        }

        return $path;
    }

    /**
     * 移除图片列表的[HOST]
     * @param array $imgList 图片列表
     * @param array $imgField 图片字段列表
     * @param bool $checkHost 是否检查域名|[true]的话检测图片域名是否为合法图片域名是的话才操作
     * @return array
     */
    static function removeImgHost($imgList = [], $imgField = [], $checkHost = false) {

        // 空的无需执行
        if (empty($imgList)) return $imgList;
        // [图片列表]非数组，组成组成列表
        if (!is_array($imgList)) {
            $imgList = [$imgList];
        }

        // [图片字段列表]非数组，组成组成列表
        if (!is_array($imgField)) {
            $imgField = [$imgField];
        }

        // 循环操作
        $pathInfo = null; // 图片字段信息
        $imgHost = self::getUpYunHost(); // 合法图片域名
        foreach ($imgList as $k => $v) {

            // **** 一维数组 ****
            if (!is_array($v)) {

                // 有[合法图片字段] && 当前字段不合法 - 下一条数据
                if (!empty($imgField) && !in_array($k, $imgField)) {
                    continue;
                }
                $pathInfo = parse_url($v);
                // 不检查域名
                if (!$checkHost) {
                    $imgList[$k] = $pathInfo['path'];
                    continue;
                }
                // 其他的就是检查域名 && 域名合法
                if ($checkHost && $pathInfo['host'] == $imgHost) {
                    $imgList[$k] = $pathInfo['path'];
                    continue;
                }
                // 最后的话也就没有其他可能性了直接返回原数据
                $imgList[$k] = $v;
                continue;
            }

            // **** 二维数组 ****
            // PS：可能会不传输[图片合法字段]，默认直接返回"parse_url => path"即可，[parse_url]函数转换失败，数据都在[path]里，所以每个二级数组[value]都执行即可
            foreach ($v as $ks => $vs) {

                // 有[合法图片字段] && 当前字段不合法 - 下一条数据
                if (!empty($imgField) && !in_array($ks, $imgField)) {
                    continue;
                }
                $pathInfo = parse_url($vs);
                // 图片是空的直接返回下
                if (empty($pathInfo['path'])) {
                    continue;
                }
                // 检查图片域名 && 图片[host]不是合法域名 - 返回不操作
                if ($checkHost && $pathInfo['host'] != $imgHost) {
                    continue;
                }

                $v[$ks] = $pathInfo['path'];
            }
            $imgList[$k] = $v;
        }

        return $imgList;
    }

    /**
     * HTMl - 添加图片服务器 host主机
     * @param string $html
     * @return mixed
     */
    public static function addHtmlImgHost($html = '')
    {

        // 空的返回
        if (empty($html)) {

            return $html;
        }
        // 获取下params配置文件的第三方存储 查看域名
        $upYunHost = self::getUpYunHost();

        $pre = "/src\s*=\s*[\'|\"]?\s*s*([^>\"'\s]*)/i";
        // 先匹配出图片列表
        preg_match_all($pre, $html, $imgSrcList);

        // 去空下
        $imgSrcList = array_filter($imgSrcList);
        // 检测下是否为空
        if (empty($imgSrcList)) {

            return $html;
        }
        // 拿出来循环
        foreach ($imgSrcList[1] as $k => $v) {

            // 空的直接下一条
            if (empty($v))

                continue;

            // 如果这个链接有[host]就不添加
            $stage = parse_url($v);
            // 有域名不操作 - 只是赋值
            if (!empty($stage['host']) && !empty($stage['scheme'])) {

                $imgSrcList[2][$k] = $v;
                continue;
            }

            $imgSrcList[2][$k] = $upYunHost . $v;
            continue;
        }

        // 集体替换下
        $html = str_replace($imgSrcList[1], $imgSrcList[2], $html);

        return $html;
    }

    /**
     * HTMl - 添加图片服务器 host主机
     * @param string $html
     * @return mixed
     */
    public static function removeHtmlImgHost($html = '')
    {

        // 空的返回
        if (empty($html)) {return $html;}
        // 把域名替换没
        $host = CommonModel::getUpYunHost();

        $pre = "/src\s*=\s*[\'|\"]?\s*s*([^>\"'\s]*)/i";
        // 先匹配出图片列表
        preg_match_all($pre, $html, $imgSrcList);

        // 去空下
        $imgSrcList = array_filter($imgSrcList);
        // 检测下是否为空
        if (empty($imgSrcList)) {

            return $html;
        }
        // 拿出来循环
        foreach ($imgSrcList[1] as $k => $v) {

            // 空的直接下一条
            if (empty($v))

                continue;

            // 如果这个链接有[host]就不添加
            $stage = parse_url($v);

            // 有域名不操作 - 只是赋值
            if (!empty($stage['host']) || !empty($stage['scheme'])) {

                $imgSrcList[2][$k] = $stage['path'];
                continue;
            }

            $imgSrcList[2][$k] = $v;
            continue;
        }

        // 集体替换下
        $html = str_replace($imgSrcList[1], $imgSrcList[2], $html);

        return $html;
    }

    /**
     * 新建MongoId
     * @return string
     */
    public static function newMongoId()
    {
        // mongo 扩展是否存在这个类 - 给 7.+ php
        if (class_exists('\MongoDB\BSON\ObjectID')) {

            return strval(new \MongoDB\BSON\ObjectID());
        }

        // mongo 扩展是否存在这个类 - 给 7.+ php
        if (class_exists('\MongoId')) {

            return strval(new \MongoId());
        }

        return self::getRandomStr(24);
    }

    /**
     * 检测文件上传完成用户发送的文件路径是否存在
     * @param $file
     * @return bool
     */
    public static function uploadFileIsExists($file)
    {
        $path = \Yii::getAlias('@webroot') . $file;
        if (!file_exists($path)) {

            return false;
        }

        return true;
    }

    /**
     * 生成一个N位随机字符
     * @param int $len
     * @return string
     */
    public static function getRandomStr($len = 24)
    {
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $final = '';
        for ($i = 0; $i < $len; $i++) {

            $final .= $chars[mt_rand(0, strlen($chars) - 1)];
        }
        return $final;
    }

    /**
     * 生成 规定位数 规定区间的 随机小数
     * @param int $min
     * @param int $max
     * @param int $len
     * @return int
     */
    public static function randFloat($min = 0, $max = 1, $len = 2)
    {

        $len_ = 1;
        for ($i = 1; $i <= $len; $i++) {

            $len_ = $len_ . 0;
        }

        $len_ = intval($len_);

        $n = rand($min * $len_, $max * $len_) / $len_;

        return floor($n * $len_) / $len_;
    }

    /**
     * 生成一个N位随机数字
     * @param int $len
     * @return string
     */
    public static function randInt($len = 24)
    {
        $chars = '0123456789';
        $final = '';
        for ($i = 0; $i < $len; $i++) {

            $final .= $chars[mt_rand(0, strlen($chars) - 1)];
        }
        return intval($final);
    }

    /**
     * 获取[Model]返回的错误
     * @param array $error 错误数组
     * @param int $reKeys 返回指定键
     * @return array|null
     */
    public static function getModelError($error = [], $reKeys = 0)
    {

        // code 列表
        $key_list = [200, 201, 400, 403];

        // 空的错误信息|错误信息长度小于等于 0
        if (empty($error) || count($error) <= 0) {

            return [
                'msg' => '请求频繁稍，请后尝试',
                'code' => 500,
                'column' => 'unknown',
                'errorHint' => null
            ];
        }

        // 不是数组 塑造数组
        if (!is_array($error))
            $error = [
                500 => [$error]
            ];

        $transitErr = [];
        foreach ($error as $k => $v) {

            // 还是数组取出最后一个操作
            if (is_array($v)) $v = end($v);
            // 不是数组做返回：
            $transitErr['msg'] = self::chineseErr($v);
            $transitErr['code'] = $k;
            $transitErr['column'] = $k;
            $transitErr['errorHint'] = $v;
            // 如果传输$k 不是0...直接用它
            if ($reKeys !== 0 && in_array($k, $key_list)) {

                $transitErr['code'] = $reKeys;
                break;
            }
        }

        return $transitErr;
    }

    /**
     * 过滤掉某些英文字符
     * @param string $error 要替换的字符串
     * @return mixed|string
     */
    public static function chineseErr($error = '')
    {

        // 不是字符串直接返回
        $parIsStr = false;
        if (is_string($error)) {
            $error = [$error];
            $parIsStr = true;
        }

        $replace = [
            ' cannot be blank' => '不能为空',
            ' must be an integer' => '必须是一个数字',
            ' must be a string' => '必须是一条字符串',
            ' has already been taken' => '已经存在了'
        ];

        foreach ($error as $k => $v) {

            // 还是数组则是多维数组 在执行下
            if (is_array($v)) $v = self::chineseErr($v);

            $error[$k] = str_replace(array_keys($replace), array_values($replace), $v);
        }

        return $parIsStr ? end($error) : $error;
    }

    /**
     * 验证手机号是否合法
     * @param $phone
     * @return bool
     */
    public static function validatePhone($phone)
    {

        $chars = "/^13[0-9]{1}[0-9]{8}$|15[0-9]{1}[0-9]{8}$|18[0-9]{1}[0-9]{8}$|17[0-9]{1}[0-9]{8}$/";

        if (preg_match($chars, $phone)) {

            return true;

        }

        return false;
    }

    /**
     * 塑造[MODEL]错误信息
     * @param string $attribute
     * @param string $error
     * @return array
     */
    public static function renderModelError($attribute = '', $error = '')
    {

        $errors = [];
        $errors[$attribute][] = $error;

        return $errors;
    }

    /**
     * [xml]转为[array]
     * @param string $xml
     * @return mixed|string
     */
    public static function xmlToArray($xml = '')
    {

        if (!$xml) {
            return '';
        }

        //将XML转为array
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $values;
    }

    /**
     * 数组转[xml]字符
     * @param array $params
     * @return string
     */
    public static function arrayToXml($params = [])
    {

        if (empty($params))

            return '';

        $xml = "<xml>";
        foreach ($params as $key => $val) {

            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }

        $xml .= "</xml>";
        return $xml;
    }

    /**
     * 根据大写字母分割字符串
     * @param string $s 操作字符
     * @param bool $isSmall 是否小些化
     * @return array[]|false|string|string[]
     */
    public static function splitAtUpperCase($s = '', $isSmall = true)
    {

        $s = preg_split('/(?=[A-Z])/', $s, -1, PREG_SPLIT_NO_EMPTY);

        // 需要转为小写
        if ($isSmall) {

            // 循环数组
            foreach ($s as $k => $v) {

                // 转为小写
                $s[$k] = strtolower($v);
            }
        }

        return $s;
    }

    /**
     * 小数四舍五入操作
     * @param float $floatNumber 小数
     * @param int $len 保留长度[默认：2]
     * @return float
     */
    public static function decimalFiveUp($floatNumber = 0.000, $len = 2)
    {

        $floatNumber = round($floatNumber, $len);

        return $floatNumber;
    }

    /**
     * 小数进一操作
     * @param float $floatNumber 小数
     * @param int $len 保留长度[默认：2]
     * @return float|int
     */
    public static function decimalUp($floatNumber = 0.000, $len = 2)
    {

        // 先来塑造 操作数
        $zero = 1;
        for ($i = 1; $i <= $len; $i++) {
            $zero .= 0;
        }
        $zero = intval($zero);

        $floatNumber = ceil($floatNumber * $zero) / $zero;

        return $floatNumber;
    }

    /**
     * 创建一个目录
     * @param $path string 全路径
     * @return bool|string true 文件创建成功或者已经存在并且可以写入
     *                     string 文件存在没有权限或者创建失败
     */
    public static function mkdir($path)
    {
        if (is_dir($path)) {
            if (is_writable($path)) {
                return true;
            } else {
                return '该目录已经存在且没有写入权限！' . $path;
            }
        } else {
            try {
                mkdir($path, 0777, true);
                return true;
            } catch (\Exception $e) {
                return $e->getMessage() . ' 错误路径： ' . $path;
            }
        }
    }

    /**
     * 数量以文本展示
     * @param int $num
     * @return int|string
     */
    public static function getNumShort($num = 0)
    {

        // 先转为数字
        $num = intval($num);

        // 首先小于 1k 直接返回
        if ($num < 1000) {

            return $num;
        }

        // 数目 / 1000 大于等于 1，小于 9 就是 千单位
        $transit = intval($num / 1000);
        if ($transit >= 1 && $transit <= 9) {

            return $transit . '千+';
        }

        // 数目 / 10000 大于等于 1，小于 9999 就是 万单位
        $transit = intval($num / 10000);
        if ($transit >= 1 && $transit <= 9999) {

            return $transit . '万+';
        }

        // 数目 / 10000000 大于等于 1，小于 9999 就是 亿单位 -- 999999
        $transit = intval($num / 10000000);
        if ($transit >= 1 && $transit <= 9999999) {

            return $transit . '亿+';
        }

        return '1兆+';
    }

    /**
     * base64 url 编码
     * @param $string
     * @return mixed|string
     */
    public static function base64UrlEncode($string)
    {

        $data = base64_encode($string);
        $data = str_replace(array('+', '/', '='), array('-', '_', ''), $data);
        return $data;
    }

    /**
     * base64 url 解码
     * @param $string
     * @return mixed|string
     */
    public static function base64UrlDecode($string)
    {

        $data = str_replace(array('-', '_'), array('+', '/'), $string);
        $mod4 = strlen($data) % 4;
        if ($mod4) {

            $data .= substr('====', $mod4);
        }
        return base64_decode($data);
    }

    /**
     * 手机号加密中间四位数
     * @param $phone
     * @return mixed
     */
    public static function phoneEncode($phone)
    {

        $phone = substr_replace($phone, '****', 3, 4);
        return $phone;
    }

    /**
     * 给某连接添加参数
     * @param string $url
     * @param array $params
     * @return string
     */
    public static function addParams($url = '', $params = [])
    {

        // 先将连接格式化为数组
        $urlArray = parse_url($url);
        $urlArray['query'] = empty($urlArray['query']) ? '' : $urlArray['query'];
        // 取出参数将参数以[&]分割
        $urlParStage = explode('&', $urlArray['query']);
        $stage = []; // 公共暂存
        $urlPar = []; // 参数[key => value]格式
        foreach ($urlParStage as $k => $v) {
            $stage = explode('=', $v);
            $urlPar[$stage[0]] = empty($stage[1]) ? '' : $stage[1];
        }
        // 将需要添加的参数循环加入
        foreach ($params as $k => $v) {
            $urlPar[$k] = $v;
        }
        $stage = []; // 公共暂存 - 初始化
        // 将最终参数[k => v]组合为以[=]连接的一维数组
        foreach ($urlPar as $k => $v) {
            $stage[] = $k . '=' . $v;
        }
        $stage = implode($stage, '&');
        $urlArray['query'] = $stage;
        $end = $urlArray['scheme'] . '://' .
            $urlArray['host'] .
            $urlArray['path'] . '?' .
            $urlArray['query'];

        return $end;
    }

    /**
     * 去除全部空格
     * @param $str
     * @return mixed|string
     */
    public static function clearAllSpa($str) {
        $search = array(' ', '　', 'ㅤ', ' ', '	', '  ');
        $replace = '';
        $str = str_replace($search, $replace, $str);
        $str = trim($str);
        return $str;
    }
}
